package com.tunnel.home.server;

import java.io.BufferedReader;
import java.io.DataOutputStream;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.Calendar;
import java.util.Date;
import java.util.Map;

import org.axe.annotation.ioc.Autowired;
import org.axe.annotation.ioc.Service;
import org.axe.annotation.persistence.Tns;
import org.axe.util.JsonUtil;
import org.axe.util.MD5Util;
import org.axe.util.StringUtil;

import com.tunnel.common.util.LogUtil;
import com.tunnel.home.common.Constant;
import com.tunnel.home.common.SysConfig;
import com.tunnel.home.dao.PayLogDao;
import com.tunnel.home.dao.UserDao;
import com.tunnel.home.entity.PayLog;
import com.tunnel.home.entity.User;

@Service
public class PayService {
	
	@Autowired
	private PayLogDao payLogDao;
	@Autowired
	private UserDao userDao;

	/**
	 * 支付成功的回调通知
	 * 做3件事：
	 * 1.核对商品
	 * 2.看是不是重复通知
	 * @throws Exception 
	 */
	@Tns
	public void payNotify(Map<String, Object> map) throws Exception{
		String outTradeNo = map.get("outTradeNo").toString();
		
		PayLog payLog = payLogDao.get(outTradeNo);
		if(payLog == null){
			throw new Exception("支付记录不存在");
		}
		if(payLog.getStatus() == 1){
			throw new Exception("支付记录状态已经是：支付成功");
		}
		
		String fee = map.get("money").toString();
		if(!payLog.getFee().equals(fee)){
			throw new Exception("金额不正确");
		}
		
		int sqlResult = payLogDao.setNotify(outTradeNo, JsonUtil.toJson(map));
		if(sqlResult != 1){
			throw new Exception("修改支付记录状态，设置支付记录回调报文，失败！sqlResult:"+sqlResult);
		}
		
		//给用户增加会员时间
		User user = userDao.getUser(payLog.getUserId());
		if(user == null){
			throw new Exception("支付记录里的userId没有找到数据");
		}
		
		Date expireTime = user.getExpireTime();
		if(expireTime == null){
			expireTime = new Date();//重来没充值过
		}else{
			//如果已账号经过期了，则也要用当前时间开始计算
			if(user.getStatus() == 0){
				expireTime = new Date();
			}
		}
		
		Integer addDays = Constant.ADD_DAYS_MAP.get(payLog.getGoods());
		if(addDays == null){
			throw new Exception("支付记录里的商品，没有找到配置天数");
		}
		
		Calendar calendar = Calendar.getInstance();
		calendar.setTime(expireTime);
		calendar.add(Calendar.DAY_OF_YEAR, addDays);
		expireTime = calendar.getTime();
		sqlResult = userDao.addExpireDays(user.getId(), expireTime);
		if(sqlResult != 1){
			throw new Exception("修改用户账户过期时间，失败！sqlResult:"+sqlResult);
		}
	}
	
	/**
	 * 对接的YunGouOS
	 * https://open.pay.yungouos.com/#/api/api/pay/wxpay/nativePay
	 * 返回微信扫码支付二维码地址
	 */
	@Tns
	public String createWxScanCodePayOrder(long userId,String fee,String goods)throws Exception{
		
		//保存到数据库
		PayLog payLog = new PayLog();
		payLog.setOutTradeNo(StringUtil.getRandomString(32));
		payLog.setUserId(userId);
		payLog.setFee(fee);
		payLog.setGoods(goods);
		payLog.setCreateTime(new Date());
		//1天有效期
		payLog.setExpireTime(new Date(payLog.getCreateTime().getTime()+Constant.MIN_SECONDS_OF_24_HOURS));//1天后过期
		payLog = payLogDao.saveEntity(payLog);//保存下，确保out_order_no不重复
		
		StringBuilder paramsBuf= new StringBuilder();
		//订单号（不可重复）
		paramsBuf.append("out_trade_no=").append(payLog.getOutTradeNo());
		//支付金额（范围：0.01~999999）
		paramsBuf.append("&total_fee=").append(fee);
		//微信支付商户号
		paramsBuf.append("&mch_id=").append(SysConfig.mch_id());
		//商品简单描述
		paramsBuf.append("&body=").append(goods);
		//返回类型（1、返回微信原生的支付连接需要自行生成二维码；2、直接返回付款二维码地址，页面上展示即可。不填默认1 ）
		paramsBuf.append("&type=").append("2");
		//异步回调地址，用户支付成功后系统将会把支付结果发送到该地址，不填则无回调
		paramsBuf.append("&notify_url=").append(SysConfig.notify_url());
		
		//签名，只有必填参数才参与签名，按照阿斯克码顺序，最后加上key，再md5，再转大写
		String sign = "body="+goods+"&mch_id="+SysConfig.mch_id()+"&out_trade_no="+payLog.getOutTradeNo()+"&total_fee="+fee+"&key="+SysConfig.pay_key();
		sign = MD5Util.getMD5Code(sign).toUpperCase();
		paramsBuf.append("&sign=").append(sign);
		
		String requestPayLoad = paramsBuf.toString();
		payLog.setPayLoad(requestPayLoad);
		payLog = payLogDao.saveEntity(payLog);
		
		String response = sendPostRequest("https://api.pay.yungouos.com/api/pay/wxpay/nativePay", requestPayLoad);
		if(response.contains("下单成功")){
			Map<?,?> result = JsonUtil.fromJson(response, Map.class);
			String payCodeUrl = result.get("data").toString();
			payLogDao.setPayCodeUrl(payLog.getId(), payCodeUrl);
			return payCodeUrl;
		}else{
			LogUtil.log("userId:"+userId+"，请求报文："+payLog.getPayLoad()+"，返回报文："+response);
			throw new Exception("下单失败");
		}
	}
	
	/**
	 * 不使用axe框架的httputil，是因为支付接口要求form提交
	 */
	private String sendPostRequest(String url,String requestPayLoad) throws Exception{
		DataOutputStream out = null;
		BufferedReader in = null;
		String result = "";
		HttpURLConnection conn = null;
		try {
			URL realUrl = new URL(url);
			// 打开和URL之间的连接
			conn = (HttpURLConnection)(realUrl.openConnection());
			// 设置通用的请求属性
			conn.setConnectTimeout(10000);//10秒超时
			conn.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
			conn.setRequestProperty("Connection", "Keep-Alive");
			conn.setRequestMethod("POST");
			// 发送POST请求必须设置如下两行
			conn.setDoOutput(true);
			conn.setDoInput(true);
			// 获取URLConnection对象对应的输出流
			out = new DataOutputStream(conn.getOutputStream());
			// 发送请求参数
			//进行编码
			out.write(requestPayLoad.getBytes("utf-8"));
			// flush输出流的缓冲
			out.flush();
			// 定义BufferedReader输入流来读取URL的响应
			in = new BufferedReader(new InputStreamReader(conn.getInputStream(), "utf-8"));
			String line;
			while ((line = in.readLine()) != null) {
				result += line;
			}
		} catch (Exception e) {
			throw e;
		}
		// 使用finally块来关闭输出流、输入流
		finally {
			try {
				if (out != null) {
					out.close();
				}
			} catch (Exception e2) {
				LogUtil.error(new Exception("关闭输出流出现异常！url:"+url+" 参数:"+requestPayLoad));
				LogUtil.error(e2);
			}
			try {
				if (in != null) {
					in.close();
				}
			} catch (Exception e2) {
				LogUtil.error(new Exception("关闭输入流出现异常！url:"+url+" 参数:"+requestPayLoad));
				LogUtil.error(e2);
			}
			try {
				if (conn != null) {
					conn.disconnect();
				}
			} catch (Exception e2) {
				LogUtil.error(new Exception("关闭连接异常！url:"+url+" 参数:"+requestPayLoad));
				LogUtil.error(e2);
			}
		}
		return result;
	}
	
}
